import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import produce from 'immer'
import cloneDeep from 'lodash.clonedeep'
import { arrayMove } from '@dnd-kit/sortable'
import { ComponentPropsType } from '../../components/QuestionComponents'
import { getNextSelectId } from './utils'
import { nanoid } from 'nanoid'

export type ComponentInfoType = {
  fe_id: string
  type: string
  title: string
  isHidden?: boolean
  isLocked?: boolean
  props: ComponentPropsType
}

export type ComponentsStateType = {
  selectedId: string
  componentList: ComponentInfoType[]
  copiedComponent: ComponentInfoType | null
}
const INIT_STATE: ComponentsStateType = {
  selectedId: '',
  componentList: [],
  copiedComponent: null
}

export const componentSlice = createSlice({
  name: 'components',
  initialState: INIT_STATE,
  reducers: {
    // reset
    resetComponents: (state: ComponentsStateType, action: PayloadAction<ComponentsStateType>) => {
      return action.payload
    },
    // changeSelectedId: (state: ComponentsStateType, action: PayloadAction<string>) => {
    //   return action.payload.
    // }
    changeSelectedId: produce((draft: ComponentsStateType, action: PayloadAction<string>) => {
      console.log('draft', draft)
      draft.selectedId = action.payload
    }),
    addComponent: produce(
      (state: ComponentsStateType, action: PayloadAction<ComponentInfoType>) => {
        const newComponent = action.payload
        const { selectedId, componentList } = state
        const index = componentList.findIndex(c => c.fe_id == selectedId)
        if (index < 0) {
          state.componentList.push(newComponent)
        } else {
          state.componentList.splice(index + 1, 0, newComponent)
        }

        state.selectedId = newComponent.fe_id
      }
    ),
    // 修改组件属性
    changeComponentProps: produce(
      (
        state: ComponentsStateType,
        action: PayloadAction<{ fe_id: string; newProps: ComponentPropsType }>
      ) => {
        const { fe_id, newProps } = action.payload
        const curComp = state.componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.props = {
            ...curComp.props,
            ...newProps
          }
        }
      }
    ),
    removeSelectComponent: produce((state: ComponentsStateType) => {
      const { componentList = [], selectedId = '' } = state
      const newSelectId = getNextSelectId(selectedId, componentList)
      const index = componentList.findIndex(c => c.fe_id === selectedId)
      componentList.splice(index, 1)

      state.selectedId = newSelectId
    }),
    changeComponentHidden: produce(
      (state: ComponentsStateType, action: PayloadAction<{ fe_id: string; isHidden: boolean }>) => {
        const { componentList = [], selectedId = '' } = state
        const { fe_id = '', isHidden } = action.payload
        let newSelectId = ''
        // hidden
        if (isHidden) {
          newSelectId = getNextSelectId(fe_id, componentList)
        } else {
          newSelectId = fe_id
        }

        state.selectedId = newSelectId

        const curComp = componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.isHidden = isHidden
        }
      }
    ),
    changeComponentLocked: produce(
      (state: ComponentsStateType, action: PayloadAction<{ fe_id: string }>) => {
        const { fe_id } = action.payload
        const curComp = state.componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.isLocked = !curComp.isLocked
        }
      }
    ),
    copySelectComponent: produce((state: ComponentsStateType) => {
      const { componentList = [], selectedId } = state
      const selectComponent = componentList.find(c => c.fe_id === selectedId) || null
      if (selectComponent === null) return

      state.copiedComponent = cloneDeep(selectComponent)
    }),
    pasteCopiedComponent: produce((state: ComponentsStateType) => {
      const { copiedComponent } = state
      if (copiedComponent == null) return

      copiedComponent.fe_id = nanoid()

      const { selectedId, componentList } = state
      const index = componentList.findIndex(c => c.fe_id == selectedId)
      if (index < 0) {
        state.componentList.push(copiedComponent)
      } else {
        state.componentList.splice(index + 1, 0, copiedComponent)
      }

      state.selectedId = copiedComponent.fe_id
    }),
    selectPrevComponent: produce((state: ComponentsStateType) => {
      const { selectedId, componentList } = state
      const selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)

      if (selectedIndex < 0) return
      if (selectedIndex <= 0) return

      state.selectedId = componentList[selectedIndex - 1].fe_id
    }),
    selectNextComponent: produce((state: ComponentsStateType) => {
      const { selectedId, componentList } = state
      const selectedIndex = componentList.findIndex(c => c.fe_id === selectedId)

      if (selectedIndex < 0) return
      if (selectedIndex + 1 == componentList.length) return

      state.selectedId = componentList[selectedIndex + 1].fe_id
    }),

    // 修改组件标题
    changeComponentTitle: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ fe_id: string; title: string }>) => {
        const { title, fe_id } = action.payload
        const curComp = draft.componentList.find(c => c.fe_id === fe_id)
        if (curComp) curComp.title = title
      }
    ), // 移动组件位置
    moveComponent: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ oldIndex: number; newIndex: number }>
      ) => {
        const { componentList: curComponentList } = draft
        const { oldIndex, newIndex } = action.payload

        draft.componentList = arrayMove(curComponentList, oldIndex, newIndex)
      }
    )
  }
})

export const {
  resetComponents,
  changeSelectedId,
  addComponent,
  changeComponentProps,
  removeSelectComponent,
  changeComponentHidden,
  changeComponentLocked,
  copySelectComponent,
  pasteCopiedComponent,
  selectPrevComponent,
  selectNextComponent,
  changeComponentTitle,
  moveComponent
} = componentSlice.actions
export default componentSlice.reducer
